// This is the code for the BNs inference
//
//  'The second project homework for Artifical Intelligence'
// 
// Yangang Wang, 2021/11/9, @SEU
//

#include <fstream>
#include <string>
#include <regex>
#include <iostream>

using namespace std;

int main()
{
	// read the mat
	// the missing element is indicated by -1
	//
	int Mat_missing[100][100];
	{
		ifstream infile("mat_missing.txt");
		if (infile.is_open()) {
			string line;
			regex term(" ");
			int lineIdx = 0;
			while (!infile.eof()) {
				if (lineIdx >= 100) break;
				getline(infile, line);
				sregex_token_iterator it(line.begin(), line.end(), term, -1);
				sregex_token_iterator end;
				for (int i = 0; it != end; it++, i++) {
					string str = *it;
					Mat_missing[lineIdx][i] = atoi(str.c_str());
				}
				lineIdx++;
			}
			infile.close();
		}
	}
    int Mat_gd[100][100];//真值
	{
		ifstream infile("mat_groudtruth.txt");
		if (infile.is_open()) {
			string line;
			regex term(" ");
			int lineIdx = 0;
			while (!infile.eof()) {
				if (lineIdx >= 100) break;
				getline(infile, line);
				sregex_token_iterator it(line.begin(), line.end(), term, -1);
				sregex_token_iterator end;
				for (int i = 0; it != end; it++, i++) {
					string str = *it;
					Mat_gd[lineIdx][i] = atoi(str.c_str());
				}
				lineIdx++;
			}
			infile.close();
		}
	}

	//统计Yi个数
	int Yi[11]={0};
	float PYi[11];//P(Yi)概率 先验概率
	int i=0,j=0,sum=0;//sum为已知元素总数
	for(i=0;i<100;i++)
	{ 
		for(j=0;j<100;j++)
		{
			if(Mat_missing[i][j]!=-1)
			{
				int temp=0;
				sum++;
				temp=Mat_missing[i][j];
				Yi[temp]++;
			}
		}
	}
	//计算P(Yi)概率
	for(int i=0;i<11;i++)
	{
		PYi[i]=(float)(Yi[i])/(sum);
        //cout<<"P(Yi)概率："<<PYi[i]<<endl;
	}
	
	//预测矩阵 Mat_predicted
	int Mat_predicted[100][100];
	for(int i=0;i<100;i++)
	{
		for (int j=0;j<100;j++)
		{
			Mat_predicted[i][j]=Mat_missing[i][j];
		}
	}
    int m=5;//超参数
    int r=m*m-1;
    //cout<<"mmmmmm:"<<r<<endl;
    /*
    贝叶斯的基本过程
    1、先验概率P(Yi)在100*100矩阵里统计得到
    2、目的是需要计算P(Yi|X)的最大值
    3、P(Yi|X)=P(X|Yi)*P(Yi)/P(X)
    4、P(X|Yi)=P(X1|Yi)*P(X2|Yi)* *P(Xr|Yi)
    接下来就是计算P(X1|Yi)\\\P(Xr|Yi)
    */
    int Yi_num_known[11]={0};//中心元素（已知）个数
    int Yi_num_unknown=0;//中心元素（未知）个数
    int offset=(m-1)/2;
    int xm_yi[r][11][11]={0};//统计中心元素yi对应的周围元素xm的数目  [r] [xm] [yi]
    for(int i=offset;i<100-offset;i++)
    {
        for(j=offset;j<100-offset;j++)
        {
            if(Mat_missing[i][j]!=-1)
            {
                int mat_ij=Mat_missing[i][j];
                Yi_num_known[mat_ij]++;
                int temp=0;
                for(int x_begin=i-offset;x_begin<=i+offset;x_begin++)
                {
                    for(int y_begin=j-offset;y_begin<=j+offset;y_begin++)
                    {
                        if(x_begin!=i && y_begin!=j)//不是中心元素
                        {
                            int mat_xy=Mat_missing[x_begin][y_begin];
                            if(mat_xy!=-1)
                            {
                                xm_yi[temp][mat_xy][mat_ij]++;
                                temp++;//表示中心元素为mat_missing[i][j],第temp位周围元素是mat_missing[x_begin][y_begin]的个数统计结果
                            }
                        }
                    }
                }
            }
            else
            {
                Yi_num_unknown++;//中心元素（未知）个数
            }
        }
    }
    //cout<<Yi_num_unknown<<endl;
/*    for(int i=0;i<11;i++)
    {
        cout<<"中心元素为"<<i<<"     "<<Yi_num_known[i]<<endl;
    }*/
    
    /*cout<<"中心元素2（已知）个数："<<Yi_num_known[2]<<endl;
    cout<<"中心元素（未知）个数："<<Yi_num_unknown<<endl;
    cout<<"中心元素为1，第一位元素为1的统计结果："<<xm_yi[1][1][1]<<endl;*/
    float Pxm_yi[r][11][11];//P(xm|yi)条件概率
    for(int temp=0;temp<r;temp++)
    {
        for(int i=0;i<11;i++)
        {
            for(int j=0;j<11;j++)
            {
                Pxm_yi[temp][i][j]=(float)xm_yi[temp][i][j]/Yi_num_known[j];
                //cout<<xm_yi[temp][i][j]<<endl;
            }
        }
    }
    int predict_true=0;//预测正确总数
    int predict_sum=0;//需要预测元素的总数  predict_true和predict_sum用来计算预测准确率 
    
    
    //3、P(Yi|X)=P(X|Yi)*P(Yi)/P(X)
    //4、P(X|Yi)=P(X1|Yi)*P(X2|Yi)* *P(Xr|Yi)
    for(int i=offset;i<100-offset;i++)
    {
        for(int j=offset;j<100-offset;j++)
        {
            if(Mat_missing[i][j]==-1)//待估计的中心元素
            {
                predict_sum++;
                float Pyi_xm[11];//需要通过P(xm|yi)和P(yi)计算的后验概率
                for(int last=0;last<11;last++)//用来不同Yi=last下的P(X|Yi)
                {
                    Pyi_xm[last]=PYi[last];
                    int temp=0;
                    for(int p=i-offset;p<=i+offset;p++)
                    {
                        for(int q=j-offset;q<=j+offset;q++)
                        {
                            if(p!=i && q!=j)
                            {
                                int mat_pq=Mat_missing[p][q];
                                if(mat_pq!=-1)
                                {
                                    Pyi_xm[last]=(float)Pyi_xm[last] * Pxm_yi[temp][mat_pq][last];//得到了Yi|xm条件下的概率
                                    temp++;
                                }
                            }
                        }
                    }
                    //cout<<Pyi_xm[last]<<endl;
                }
                
                float Max=0.0;
                int position=0;//中心元素估计值
                for(int index=0;index<11;index++)
                {
                    if(Pyi_xm[index]>Max)
                    {
                        Max=Pyi_xm[index];
                        position=index;
                    }
                }
                Mat_predicted[i][j]=position;
                if(Mat_gd[i][j]==position)
                {
                    predict_true++;
                }
                cout<<"Mat_predicted："<<position<<"    "<<"Mat_gd："<<Mat_gd[i][j]<<endl;
                cout<<"预测成功："<<predict_true<<"次"<<endl;
                cout<<"预测总数："<<predict_sum<<"次"<<endl;
            }
        }
    }
    cout<<"准确率："<<(float)predict_true/predict_sum<<endl;
    //cout<<predict_true<<endl;
	//======================
	// please fill the following code by Bayes Network training and inference
	//
	// Yangang Wang, 2021/11/9, @SEU
	//

	// (1) todo...

	//======================
	// You can compare the result with groudtruth data
	// read the groudtruth data
	
	// fill the comparing code here
	//
	// Yangang Wang, 2021/11/9, @SEU
	//

	// (2) todo...

	getchar();
	return 0;
}